package com.fudan.biz.data.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.fudan.biz.data.dao.FieldMetaDao;
import com.fudan.es.entity.FieldMeta;
import com.fudan.framework.base.BaseController.PageBean;
import com.fudan.framework.base.BaseDao;
import com.fudan.framework.base.DaoService;
import com.fudan.framework.utils.StringUtils;

@Service
public class FieldMetaService extends DaoService<FieldMeta>{

	private static ConcurrentHashMap<String, Map<String,FieldMeta>> fieldMap = new ConcurrentHashMap<>();

	@Autowired
	private FieldMetaDao fieldMetaDao;

	public void saveAll(List<FieldMeta> fields) {
		fieldMetaDao.saveAll(fields);
	}

	public FieldMeta findOneById(Integer id) {
		return fieldMetaDao.findById(id).get();
	}

	public Map<String,FieldMeta> getFieldsByDsId(String dsId) {
		if(fieldMap.containsKey(dsId)) {
			return fieldMap.get(dsId);
		}
		List<FieldMeta> fields = fieldMetaDao.getAllFieldByIndex(dsId);
		Map<String,FieldMeta> map = new HashMap<>();
		for (FieldMeta fieldMeta : fields) {
			map.put(fieldMeta.getName(), fieldMeta);
		}
		fieldMap.put(dsId, map);
		return map;
	}

	public List<FieldMeta> getFieldsByPage(String dsId,PageBean pageBean) {
		return fieldMetaDao.getFieldsByPage(dsId,(pageBean.getPage()-1)*pageBean.getSize(),pageBean.getSize());
	}
	public List<FieldMeta> getFieldByDsId(String id,String key) {
		Specification<FieldMeta> specification = new Specification<FieldMeta>() {
			@Override
			public Predicate toPredicate(Root<FieldMeta> root, CriteriaQuery<?> query,
					CriteriaBuilder criteriaBuilder) {
				Predicate condition = null;
				if(id != null) {
					condition = criteriaBuilder.equal(root.get("dsId"), id);
				}
				if(key != null && !"".equals(key.trim())) {
					Predicate keyP = criteriaBuilder.or(criteriaBuilder.like(root.get("alias"), "%"+key+"%"),criteriaBuilder.like(root.get("name"), "%"+key+"%"));
					condition = criteriaBuilder.and(condition,keyP);
				}
				if(condition!=null) {
					query.where(condition);
				}
				return null;
			}};
		return fieldMetaDao.findAll(specification);
	}

	public List<FieldMeta> getFieldByQuery(final FieldMeta fieldMeta,PageBean pageBean) {
		Specification<FieldMeta> specification = new Specification<FieldMeta>() {
			@Override
			public Predicate toPredicate(Root<FieldMeta> root, CriteriaQuery<?> query,
					CriteriaBuilder criteriaBuilder) {
				Predicate condition = null;

				Integer dsId = fieldMeta.getDsId();
				if(dsId != null) {
					condition = criteriaBuilder.equal(root.get("dsId"), dsId);
				}
				String name = fieldMeta.getName();
				if(name!=null && !name.equals("")) {
					if(condition == null) {
						condition = criteriaBuilder.like(root.get("name"),StringUtils.concat("%",name,"%"));
						condition = criteriaBuilder.or(condition,criteriaBuilder.like(root.get("alias"), StringUtils.concat("%",name,"%")));
					}else {
						Predicate c = criteriaBuilder.like(root.get("name"),StringUtils.concat("%",name,"%"));
						c = criteriaBuilder.or(c,criteriaBuilder.like(root.get("alias"), StringUtils.concat("%",name,"%")));
						condition = criteriaBuilder.and(condition,c);
					}
				}
				Boolean aggregatable = fieldMeta.getAggregatable();
				if(aggregatable != null&&aggregatable) {
					if(condition == null) {
						condition = criteriaBuilder.equal(root.get("aggregatable"), aggregatable);
					}else {
						condition = criteriaBuilder.and(condition,criteriaBuilder.equal(root.get("aggregatable"), aggregatable));
					}
				}
				Boolean searchable = fieldMeta.getSearchable();
				if(searchable != null&&searchable) {
					if(condition == null) {
						condition = criteriaBuilder.equal(root.get("searchable"), searchable);
					}else {
						condition = criteriaBuilder.and(condition,criteriaBuilder.equal(root.get("searchable"), searchable));
					}
				}
				if(condition!=null) {
					query.where(condition);
				}
				return null;
			}};
		return fieldMetaDao.findAll(specification,PageRequest.of(pageBean.getPage()-1, pageBean.getSize())).getContent();
	}

	public Long countFieldByQuery(FieldMeta fieldMeta) {
		Specification<FieldMeta> specification = new Specification<FieldMeta>() {
			@Override
			public Predicate toPredicate(Root<FieldMeta> root, CriteriaQuery<?> query,
					CriteriaBuilder criteriaBuilder) {
				Predicate condition = null;
				Integer dsId = fieldMeta.getDsId();
				if(dsId != null) {
					condition = criteriaBuilder.equal(root.get("dsId"), dsId);
				}
				String name = fieldMeta.getName();
				if(name!=null && !name.equals("")) {
					if(condition == null) {
						condition = criteriaBuilder.like(root.get("name"),StringUtils.concat("%",name,"%"));
						condition = criteriaBuilder.or(condition,criteriaBuilder.like(root.get("alias"), StringUtils.concat("%",name,"%")));
					}else {
						Predicate c = criteriaBuilder.like(root.get("name"),StringUtils.concat("%",name,"%"));
						c = criteriaBuilder.or(c,criteriaBuilder.like(root.get("alias"), StringUtils.concat("%",name,"%")));
						condition = criteriaBuilder.and(condition,c);
					}
				}
				Boolean aggregatable = fieldMeta.getAggregatable();
				if(aggregatable != null&&aggregatable) {
					if(condition == null) {
						condition = criteriaBuilder.equal(root.get("aggregatable"), aggregatable);
					}else {
						condition = criteriaBuilder.and(condition,criteriaBuilder.equal(root.get("aggregatable"), aggregatable));
					}
				}
				Boolean searchable = fieldMeta.getSearchable();
				if(searchable != null&&searchable) {
					if(condition == null) {
						condition = criteriaBuilder.equal(root.get("searchable"), searchable);
					}else {
						condition = criteriaBuilder.and(condition,criteriaBuilder.equal(root.get("searchable"), searchable));
					}
				}
				if(condition!=null) {
					query.where(condition);
				}
				return null;
			}};
		return fieldMetaDao.count(specification);
	}

	public List<FieldMeta> getFieldByName(String dsId,String name,PageBean pageBean) {
		return fieldMetaDao.getFieldsByName(dsId, name,pageBean.getPageIndex(),pageBean.getSize());
	}

	public FieldMeta findFieldByName(String dsId,String name) {
		return fieldMetaDao.findFieldByName(dsId, name);
	}

	public Long countFieldsByName(String dsId,String name) {
		return fieldMetaDao.countFieldsName(dsId, name);
	}

	public Long countFields(String dsId) {
		return fieldMetaDao.countFields(dsId);
	}

	@Transactional
	public void updateAlias(String id,String alias) {
		fieldMetaDao.updateAlias(id, alias);
	}

	@Override
	protected BaseDao<FieldMeta> injectDao() {
		return fieldMetaDao;
	}
}
